/* 算法实现模板 */
import AlgorithmBase from "./AlgorithmBase";
import { mdRender} from "../../../common/Common";

import { showMathStringInTable } from "../../../visual/Table2D";
import { drawDecisionTree } from "../../../visual/Tree2D";
import { DeNode } from "../../../common/DecisionTreeFuncs";

import 'katex/dist/katex.min.css';


class CARTPruning extends AlgorithmBase{
  constructor(){
    super('CARTPruning');

    this.model          = {dataSet:[ ],label:[ ],alpha:10.0}

    this.descriptionUrl = `${this.homepage}/data/slm/ch5/5.7/README.md`;
    this.datasetUrl     = `${this.homepage}/data/slm/ch5/5.7/dataset.json`;

    this.trainLog = [];
    this.len = 0
    this.Ct = 0 
    this.max = 0
    this.flag = 0
    this.node_name_ = ''
    this.cmd =''
    this.width = 0
  }
  init(){ 
    this.reset();

    this.initTrainDS();
  }
  
  reset(){
    this.dataset = undefined;
    this.trainDS = undefined;
    this.model          = {dataSet:[ ],label:[ ],alpha:10.0}

    this.clear();

    this.initDescription();
    this.updateModel();
  }

  loadModel(json){
    if(json.TrainDS){
      if(json.TrainDS instanceof Array){
        this.trainDSList = [];
        for(let i = 0, il = json.TrainDS.length; i < il; i++){
          const dat = json.TrainDS[i];
          this.trainDSList.push(dat);
        }
        this.trainDS = this.trainDSList[0];
      }
      else{
        let trainDS = json.TrainDS;
        this.trainDS = trainDS;
      }
    }
    return this.trainDS
  }
  
  // 模型UI
  initModelUI(){
    this.modelDiv = this.addDiv(this.domElementList.model);
  }

  // 渲染模型到页面
  updateModel(data, label, tree){

    // 显示数据集
    if(this.trainDS){
      if(data === undefined) data = this.trainDS.dataSet;
      if(label === undefined) label = this.trainDS.label;
      if(tree === undefined) tree = this.trainDS.tree;

      var table_data = [];

      var data_label_ = ["ID"];
      for(var i=0;i<label.length;i++){
        data_label_.push("\\textbf{"+label[i]+"}")
      }

      table_data.push(data_label_);

      for(var j=0;j<data.length;j++){
        var data_=[]
        data_.push((j+1).toString())
        for(var k=0;k<data[j].length;k++){
          data_.push("\\textbf{"+data[j][k]+"}")
        }
        table_data.push(data_)
      }

      console.log(data);

      showMathStringInTable(this.inputDiv,table_data);
      drawDecisionTree(this.inputDiv,tree);
      
    }
  }

  // 输入数据UI
  initInputUI(){

    // 文件选择器
    const fileSelector      = document.createElement('input');
    fileSelector.type       = 'file';
    fileSelector.hidden     = true;
    fileSelector.onchange   = this.handleFileChange.bind(this);   
    
    this.addButton(this.domElementList.input, "获取服务器数据", this.initTrainDS.bind(this));
    this.addButton(this.domElementList.input, "使用本地数据", this.openFileSelector.bind(this));
    this.domElementList.input.appendChild(fileSelector);
    this.addButton(this.domElementList.input, "训练", this.train.bind(this));
    // this.playButton = this.addButton(this.domElementList.input, "训练动画", this.trainAnimation.bind(this));
    // this.playButton.hidden = true;

    this.labelTrainTips = this.addLabel(this.domElementList.input, '');
    this.inputDiv       = this.addDiv(this.domElementList.input);

    this.fileSelector  = fileSelector;
  }

  // 输出UI
  initOutputUI(){
    this.outputDiv   = this.addDiv(this.domElementList.output);
    this.trainLogDiv = this.addDiv(this.domElementList.output);
  }

  // 获取描述md文件
  initDescription(){
    fetch(this.descriptionUrl).then((response)=>{
      return response.text();
    }).then((txt)=>{

      this.reandMD(txt, this.descriptionDiv)
    })
  }

  // 获取服务器数据集
  initTrainDS(){
    this.prepare(this.datasetUrl);
  }

  // 准备数据训练数据
  prepare(url){
    fetch(url).then((response)=>{
      return response.json();
    }).then((json)=>{
      this.trainDS = this.loadModel(json);
      console.log(this.trainDS);
      this.updateModel();
    })
  }

  openFileSelector(){
    this.fileSelector.click();
  }
  // 获取文件路径加载
  handleFileChange(event){
    const files = event.target.files;

    for(let i = 0, il = files.length; i < il; i++){
      let reader = new FileReader();
      reader.onload = (e) => {      
        this.prepare(e.target.result);
        if(i === files.length - 1){
          event.target.value = '';
        }
      };
      reader.readAsDataURL(files[i])
    }
  }

  // 训练
  train(){
    const dataSet = this.trainDS.dataSet
    const label = this.trainDS.label

    var tree = new DeNode(this.trainDS.tree)

    var tree = new DeNode(this.trainDS.tree)

    var T = []
    T.push(tree.node)

    var trainlog = []

    trainlog.push(["\\text{迭代次数}","\\text{内部结点}","g_t","a","\\text{是否剪枝}"])

    var count = 1

    while(tree.getDepth()>1){
      var new_ = new DeNode(tree.cart_purn(dataSet,label))
      if(JSON.stringify(tree.node) === JSON.stringify(new_.node)){
        break
      }
      else{
        T.push(new_.node)
        for(var i=0;i<tree.gt.length;i++){
          if(tree.gt[i]!=tree.cart_alpha){
            trainlog.push([`${count}`, `${tree.gt_name[i]}`, `${tree.gt[i]}`, `${tree.cart_alpha}`, "\\text{否}"])
          }
          else{
            trainlog.push([`${count}`, `${tree.gt_name[i]}`, `${tree.gt[i]}`, `${tree.cart_alpha}`, "\\text{是}"])
          }
        }
      }
      
      tree = new DeNode(Object.assign({}, new_.node));
      count++
    }
    
    //gini 指数不正确，需要确认
    var min = 99999999999999
    var index_t = 0
    var ginilog = ["\\text{迭代次数}","\\text{内部结点}","g_t","a","\\text{是否剪枝}"]
    for(var i=0;i<T.length;i++){
      var tree_ = new DeNode(T[i])
      var gini = tree_.cal_gini(dataSet,label)
      
      if(gini<min){
        min = gini
        index_t = i
      }
      else if(gini == min){
        var tree_i = new DeNode(T[index_t])
        if(tree_.getDepth()<tree_i.getDepth || tree_.getWidth()<tree_i.getWidth()){
          min = gini
          index_t = i
        }
      }
    }

    var end_tree = Object.assign({}, T[index_t]);

    if(this.trainLogDiv) this.trainLogDiv.innerHTML = '';
    drawDecisionTree(this.trainLogDiv, end_tree);
    showMathStringInTable(this.trainLogDiv, trainlog);

  }

}



export default CARTPruning;